import functools
from typing import List, Callable

from pywebio.output import PopupSize

from emi.bar.data import CategoryMeta
from emi.bar.db import DayDB, BarDB
from emi.config import Config
from emi.model import Market, SimpleMarket
from pywebio import output,input,pin

from emi.util import utils
from emiui.chart import echarts
from emiui.chart.model import KModel
from pywebio.output import popup, close_popup
from pywebio.pin import put_actions, pin_wait_change
from pywebio.utils import random_str

def select_category_meta(data:[SimpleMarket,List[CategoryMeta]],onResult:Callable):
    """
    选择某个行业
    :return:
    """
    if isinstance(data,SimpleMarket):
        c_metas = data.get_all_category_metas()
    else:
        c_metas = data
    def on_select(meta:CategoryMeta):
        output.close_popup()
        onResult(meta)
    def _onchange(q_text:str):
        q_text = q_text.strip()
        result = []
        COLUMN_SIZE = 2
        MAX_SIZE = COLUMN_SIZE * 4
        if q_text:
            for index,meta in enumerate(c_metas):
                if meta.name.__contains__(q_text) or meta.code.__contains__(q_text):
                    if len(result) == MAX_SIZE - 1:
                        is_last = index == len(c_metas) - 1
                        if is_last:
                            cell = output.put_button(f"{meta.name}({meta.code})",
                                                 color='light',
                                                 onclick=functools.partial(on_select,meta))
                            result.append(cell)
                        else:
                            result.append("···")
                        break
                    else:
                        cell = output.put_button(f"{meta.name}({meta.code})",
                                                 color='light',
                                                 onclick=functools.partial(on_select, meta))
                        result.append(cell)
        with output.use_scope("scm_result",clear=True):
            if not result:
                output.put_text("无结果")
                return
            gird_datas = []
            line_data = None
            for i in range(0, len(result)):
                if i % COLUMN_SIZE == 0:
                    line_data = [result[i]]
                    gird_datas.append(line_data)
                else:
                    line_data.append(result[i])
            if i in range(len(line_data), COLUMN_SIZE):
                line_data.append("")
            cell_widths = " ".join([ "200px" for i in range(0,COLUMN_SIZE)])
            output.put_grid(gird_datas, cell_widths=cell_widths)
    with output.popup("选择行业"):
        pin.put_input("scm_input",label="输入行业代码或者名称")
        pin.pin_on_change("scm_input",onchange=_onchange)
        output.put_markdown("------------")
        output.put_scope("scm_result")

        _onchange("")


def popup_chart(bar_db: BarDB, day_db: DayDB, code: str, name: str = None):
    if name is None:
        title = f"{code} 行情图"
    else:
        title = f"{name}({code})行情图"
    output.popup(title=title, content=[
        output.put_loading(),
        output.put_text("正在加载中....")
    ])
    if day_db:
        d_bars = day_db.get_bars(symbol=code)
    else:
        d_bars = []

    if bar_db:
        k_bars = bar_db.get_bars(symbol=code, with_detail=False)
        for bar in k_bars:
            ### 根据复权因子，转换到实时价格。
            bar.high = bar.high / bar.price_adjust
            bar.low = bar.low / bar.price_adjust
            bar.open = bar.open / bar.price_adjust
            bar.close = bar.close / bar.price_adjust
            bar.pre_close = bar.pre_close / bar.price_adjust
        if day_db and k_bars:
            latest_bar = k_bars[-1]
            today_bar = day_db.get_tick(code)
            if today_bar \
                    and not utils.is_same_day(latest_bar.datetime, today_bar.datetime) \
                    and today_bar.datetime > latest_bar.datetime:
                ### 行业分类数据重新复权值。
                base_price = latest_bar.close
                today_bar.open = base_price * (1 + (today_bar.open - today_bar.pre_close) / today_bar.pre_close)
                today_bar.high = base_price * (1 + (today_bar.high - today_bar.pre_close) / today_bar.pre_close)
                today_bar.low = base_price * (1 + (today_bar.low - today_bar.pre_close) / today_bar.pre_close)
                today_bar.close = base_price * (1 + (today_bar.close - today_bar.pre_close) / today_bar.pre_close)
                today_bar.pre_close = base_price
                k_bars.append(today_bar)  ## 加入当天实时数据
    else:
        k_bars = []

    width = "800px"
    height = "400px"
    tab_list = []
    if d_bars:
        k_model = KModel(is_daily=False)
        k_model.set_bar_list(d_bars)
        chart = k_model.build_chart(is_line=True,title="")
        chart.width = width
        chart.height = height
        tab_list.append({
            "title": '实时',
            "content": [output.put_html(chart.render_notebook())]
        })
    if k_bars:
        k_model = KModel(is_daily=True)
        k_model.set_bar_list(k_bars)
        k_chart = k_model.build_chart(is_line=False,title="")
        k_chart.width = width
        k_chart.height = height
        tab_list.append({
            "title": 'K线',
            "content": [output.put_html(k_chart.render_notebook())]
        })

    output.popup(title=title, content=[
        output.put_tabs(tab_list) if tab_list else output.put_text("没有行情数据！")
    ], size=PopupSize.LARGE)



async def popup_edit_config(title:str,config:Config):
    """
    弹出编辑Config对象界面
    :param title  标题
    :param config 配置对象
    """

    pass


async def popup_confirm(title, content=None, *, timeout=None):
    """Show a confirmation modal.

    :param str title: Model title.
    :param list/put_xxx() content: Model content.
    :param None/float timeout: Seconds for operation time out.
    :return: Return `True` when the "CONFIRM" button is clicked,
        return `False` when the "CANCEL" button is clicked,
        return `None` when a timeout is given and the operation times out.
    """
    if content is None:
        content = []
    if not isinstance(content, list):
        content = [content]
    action_name = random_str(10)
    content.append(put_actions(action_name, buttons=[
        {'label': 'CONFIRM', 'value': True},
        {'label': 'CANCEL', 'value': False, 'color': 'danger'},
    ]))
    popup(title=title, content=content, closable=False)
    result = await pin_wait_change(action_name, timeout=timeout)
    if result:
        result = result['value']
    close_popup()
    return result
